home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Uip / rcvtrip / rcvtrip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  15.9 KB  |  750 lines

  1. /* rcvtrip.c: trip reporting program */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Uip/rcvtrip/RCS/rcvtrip.c,v 6.0 1991/12/18 20:42:02 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Uip/rcvtrip/RCS/rcvtrip.c,v 6.0 1991/12/18 20:42:02 jpo Rel $
  9.  *
  10.  * $Log: rcvtrip.c,v $
  11.  * Revision 6.0  1991/12/18  20:42:02  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include    "util.h"
  19. #include    "retcode.h"
  20. #include    "adr.h"
  21. #include    "ap.h"
  22. #include    "chan.h"
  23. #include     "alias.h"
  24. #include    <pwd.h>
  25.  
  26. #define        NONFATAL    0    /* Nonfatal reports         */
  27. #define        FATAL        1    /* Fatal reports (exit)         */
  28. #define        TRACE        2    /* General info for debug     */
  29.  
  30. #define        EX_SENT        1
  31. #define        EX_DUP        2
  32. #define        EX_NOT_DIR    3
  33. #define        EX_PARSE_ERR    4
  34. #define        EX_ERR        99
  35.  
  36. #define        SENT        0    /* Sent out a reply         */
  37. #define        UNSENT        1    /* No reply sent - just
  38.                      * note     */
  39.  
  40. #define        REPLIED        '+'    /* A reply was sent         */
  41. #define        NOT_REPLIED    '-'    /* A reply wasn't sent         */
  42.  
  43. #define        HDR_NAM        1
  44. #define     HDR_EOH        2
  45. #define        HDR_MOR        3
  46. #define        HDR_NEW        4
  47.  
  48. #define        DAYS    * (60 * 60 * 24)
  49.  
  50. #ifndef    MAX_HEAD_LINES
  51. #define    MAX_HEAD_LINES    10
  52. #endif    /* MAX_HEAD_LINES */
  53.  
  54. extern int ap_outtype;
  55.  
  56. extern char *compress ();
  57.  
  58. int     debug = FALSE;        /* output trace messages?       */
  59. int    repeat_interval = 14 DAYS; /* repeat after this interval   */
  60. int     found_1 = FALSE;    /* true if message was sent to       */
  61. int    head_lines = 0;
  62. int    exit_alg = -1;        /* algorithm to deiced on the exit code */
  63. int    exit_code = 1;
  64.  
  65.  /* directly to recipient       */
  66. char    subj_field[LINESIZE];    /* contents of subject field       */
  67. char    _username[LINESIZE];    /* space for the users username       */
  68. char    *username = (char *) 0;    /* the users username           */
  69. char    *msg_note = "tripnote";/* where to get reply message from */
  70. char    *wholoc = "triplog";    /* where to note incoming messages */
  71. char    *sigloc = ".signature";/* where to find user's name       */
  72. char    *tripsig = "MESSAGE AGENT";
  73.  
  74. /* signature of the returned message */
  75.  
  76. AP_ptr  from_adr = NULLAP;    /* address tree for from address   */
  77. AP_ptr  sndr_adr = NULLAP;    /* - " -        sender       */
  78. AP_ptr  repl_adr = NULLAP;    /* - " -        reply-to       */
  79.  
  80. ADDR    *user_adr;
  81.  
  82. char   *find_sig ();
  83. static int exit_rc();
  84.  
  85. struct passwd *getpwuid ();
  86.  
  87. /*
  88.  *    This message is output before the users file message
  89.  */
  90. char   *text_message[MAX_HEAD_LINES+1] = {
  91.     "\tThis is an automatic reply.  Feel free to send additional",
  92.     "mail, as only this one notice will be generated.  The following",
  93.     "is a prerecorded message, sent for ", 0
  94. };
  95.  
  96. /*
  97.  *    This message is output if the users file is not readable or doesn't
  98.  *    exist. (This is where you can have some fun!)
  99.  */
  100. char   *error_txt[] = {
  101.     "\tIt appears that the person in question hasn't left a\n",
  102.     "message file, so the purpose of this message is unknown.\n",
  103.     "However it is assumed that as I, a daemon process,\n",
  104.     "have been called into existance that the person in question\n",
  105.     "is probably away for some time and won't be replying to your\n",
  106.     "message straight away.\n\nCheers,\n\tThe Mail System\n", 0
  107. };
  108.  
  109. main (argc, argv)
  110. int     argc;
  111. char  **argv;
  112. {
  113.     init (argc, argv);
  114.     parsemsg ();
  115.     doreplies ();
  116. #ifdef  PP_DEBUG
  117.     report (TRACE, 0, "exit with %d -> %d", exit_code, exit_rc(exit_code));
  118. #endif
  119.     exit (exit_rc(exit_code));
  120. }
  121.  
  122. /*
  123.  *    Initialisation - get user, setup flags etc.
  124.  */
  125.  
  126. init (argc, argv)
  127. int     argc;
  128. char  **argv;
  129. {
  130.     register struct passwd     *pwdptr;
  131.     int            opt;
  132.     extern int        optind;
  133.     extern char        *optarg;
  134.     RP_Buf            rp;
  135.  
  136.     uip_init (argv[0]);
  137.  
  138.     ap_outtype = AP_PARSE_822;    /* standardise on 822 */
  139.  
  140.     while ((opt = getopt (argc, argv, "de:Ff:l:n:s:t:u:")) != EOF)
  141.         switch (opt) {
  142.         case 'd': debug = 1;            break;
  143.         case 'e': exit_alg = atoi(optarg);    break;
  144.         case 'F': found_1 = 1;            break;
  145.         case 'f': tripsig = optarg;        break;
  146.         case 'l': wholoc = optarg;        break;
  147.         case 'n': msg_note = optarg;        break;
  148.         /* This is disapbled for the momet ... */
  149.         case 'r': opt = atoi(optarg);
  150.               if (!opt && *optarg != '0')    break;
  151.               repeat_interval = opt DAYS;    break;
  152.         case 's': sigloc = optarg;        break;
  153.         case 't': if (head_lines < MAX_HEAD_LINES)
  154.                 text_message[head_lines++] = optarg; break;
  155.         case 'u': username = optarg;        break;
  156.         }
  157. #ifdef  PP_DEBUG
  158.     report (TRACE, 0, "argc=%d, optind=%d, argv='%s' ... '%s'",
  159.             argc, optind, argv[0], argv[argc-1]);
  160. #endif
  161.     argv += optind;
  162.     argc -= optind;
  163.  
  164.     if (argc > 0)        /* we have a command line sender
  165.                  * address */
  166.     {
  167. #ifdef  PP_DEBUG
  168.         report (TRACE, 0, "argc=%d, *argv=%x=`%s'",
  169.             argc, *argv, *argv);
  170. #endif
  171.         if (*argv) parse_addr (*argv, &sndr_adr);
  172.         else report (TRACE, 0, "*argv was null !");
  173. #ifdef  PP_DEBUG
  174.         report (TRACE, 0, "*argv parsed");
  175. #endif
  176.     }
  177.  
  178.     if (username)
  179.         ;
  180.     else if ((pwdptr = getpwuid (getuid ())) == (struct passwd *) 0)
  181.         report (FATAL, EX_ERR, "Can't Identify user");
  182.     else
  183.         strcpy (username = _username, pwdptr->pw_name);
  184.  
  185.     if (head_lines) error_txt[head_lines] = (char *) 0;
  186.  
  187.     user_adr = adr_new (username, AD_ANY_TYPE, 0);
  188. #ifdef UKORDER
  189.     if (rp_isbad (ad_parse (user_adr, &rp, CH_UK_PREF)))
  190. #else
  191.     if (rp_isbad (ad_parse (user_adr, &rp, CH_USA_PREF)))
  192. #endif
  193.         report (FATAL, EX_PARSE_ERR, "Can't parse you as a mail user");
  194. }
  195.  
  196. /*
  197.  *    parse message - just a front end to the real parser
  198.  */
  199.  
  200. parsemsg ()
  201. {
  202.     if (rp_isbad (hdr_fil (stdin)))
  203.         report (FATAL, EX_PARSE_ERR, "parse of message failed");
  204. }
  205.  
  206. /*************** Routines to despatch messages ***************/
  207.  
  208. /*
  209.  *    Send replies to reply-to address if specified else
  210.  *        from and sender address.
  211.  */
  212.  
  213. doreplies ()
  214. {
  215.     if (found_1 != TRUE)
  216.         report (FATAL, EX_NOT_DIR, "Not sent directly to %s", username);
  217.  
  218.     if (repl_adr == NULLAP && from_adr == NULLAP && sndr_adr == NULLAP)
  219.         report (FATAL, EX_PARSE_ERR, "No parsable from or sender lines");
  220.  
  221. /*
  222.  *    If there were any reply-to lines, use those in preference.
  223.  */
  224.     if (repl_adr != NULLAP)
  225.         replyto (repl_adr);
  226.     else if (from_adr != NULLAP)
  227.         replyto (from_adr);
  228.     else if (sndr_adr != NULLAP)
  229.         replyto (sndr_adr);
  230. }
  231.  
  232. /*
  233.  *    Actually do the work of sending the reply.
  234.  */
  235.  
  236. replyto (aptr)
  237. AP_ptr  aptr;
  238. {
  239.     register char *cp;
  240.     register char **cpp;
  241.     AP_ptr  user, local, domain;
  242.     AP_ptr  norm;
  243.     char   *addr;
  244.     char   *ref;
  245.     char   *person;
  246.     char    buffer[LINESIZE];
  247.     FILE   *fp;
  248.     RP_Buf    rps, *rp = &rps;
  249.  
  250. #ifdef    PP_DEBUG
  251.     report (TRACE, 0, "replyto()");
  252. #endif
  253.  
  254. #ifdef UKORDER
  255.     norm = ap_normalize (aptr, CH_UK_PREF);
  256. #else
  257.     norm = ap_normalize (aptr, CH_USA_PREF);
  258. #endif
  259.     ap_t2p (norm, (AP_ptr *) 0, &user, &local, &domain, (AP_ptr *) 0);
  260.     ref = ap_p2s_nc (NULLAP, NULLAP, local, domain, NULLAP);
  261.  
  262. #ifdef    PP_DEBUG
  263.     report (TRACE, 0, "normed addr = '%s'", ref);
  264. #endif
  265.  
  266.     if (user != NULLAP)
  267.         person = user->ap_obvalue;
  268.     else
  269.         person = NULLCP;
  270.  
  271.     if (checkuser (ref)) {
  272.  
  273. #ifdef    PP_DEBUG
  274.         report (TRACE, 0, "Seen %s before", ref);
  275. #endif
  276.  
  277.         noteuser (ref, UNSENT);
  278.         free (ref);
  279.         return;
  280.     }
  281.     if (ap_t2s (norm, &addr) == (AP_ptr) NOTOK) {
  282.         report (NONFATAL, 0, "Parse error for %s", addr);
  283.         noteuser (ref, UNSENT);
  284.         free (ref);
  285.         return;
  286.     }
  287.     buffer[0] = '\0';
  288.     if (!prefix ("re:", subj_field))
  289.         strcpy (buffer, "Re: ");
  290.  
  291.     strcat (buffer, subj_field);
  292.  
  293. #ifdef    PP_DEBUG
  294.     report (TRACE, 0, "pps_1adr ('%s' %s)",
  295.         buffer, addr);
  296. #endif
  297.  
  298.     pps_1adr (buffer, addr, rp);
  299.  
  300.     if (person != NULLCP) {
  301.         compress (person, person);
  302.         sprintf (buffer, "\nDear %s,\n", person);
  303.  
  304. #ifdef    PP_DEBUG
  305.         report (TRACE, 0, "1st line %s", buffer);
  306. #endif
  307.  
  308.         pps_txt (buffer, rp);
  309.     }
  310.  
  311. #ifdef    PP_DEBUG
  312.     report (TRACE, 0, "start builtin message");
  313. #endif
  314.  
  315.     for (cpp = text_message; *cpp != NULLCP; cpp++)
  316.     {    if (cpp != text_message) pps_txt ("\n", rp);
  317.         pps_txt (*cpp, rp);
  318.     }
  319.     if ((cp = find_sig ()) != NULLCP)
  320.         pps_txt (cp, rp);
  321.     else if (user_adr && user_adr -> ad_r822adr)
  322.         pps_txt (user_adr -> ad_r822adr);
  323.     else
  324.         pps_txt (username, rp);
  325.     pps_txt ("\n\n\n", rp);
  326.  
  327.     if ((fp = fopen (msg_note, "r")) != (FILE *) 0) {
  328.  
  329. #ifdef    PP_DEBUG
  330.         report (TRACE, 0, "processing file %s", msg_note);
  331. #endif
  332.  
  333.         pps_file (fp, rp);
  334.         fclose (fp);
  335.     }
  336.     else {
  337.  
  338. #ifdef    PP_DEBUG
  339.         report (TRACE, 0, "Sending built in error message");
  340. #endif
  341.  
  342.         for (cpp = error_txt; *cpp != NULLCP; cpp++)
  343.             pps_txt (*cpp, rp);
  344.     }
  345.  
  346. #ifdef    PP_DEBUG
  347.     report (TRACE, 0, "ml_end(OK)");
  348. #endif
  349.  
  350.     if (pps_end (OK, rp) == OK)
  351.         noteuser (ref, SENT);
  352.     else
  353.         noteuser (ref, UNSENT);
  354.     free (ref);
  355.     free (addr);
  356. }
  357.  
  358. /*************** Routines to pick apart the message ***************/
  359.  
  360. /*
  361.  *    The actual picking out of headers
  362.  */
  363.  
  364. hdr_fil (msg)
  365. FILE   *msg;            /* The message file             */
  366. {
  367.     char    line[LINESIZE];    /* temp buffer             */
  368.     char    name[LINESIZE];    /* Name of header field         */
  369.     char    contents[LINESIZE];    /* Contents of header field     */
  370.  
  371. #ifdef    PP_DEBUG
  372.     report (TRACE, 0, "hdr_fil()");
  373. #endif
  374.  
  375.     if (msg == (FILE *) NULL) {
  376.         report (FATAL, EX_PARSE_ERR, "NULL file pointer");
  377.         return (RP_NO);    /* not much point doing anything
  378.                  * else */
  379.     }
  380. /* process the file    */
  381.  
  382.     for (;;) {
  383.         if (fgets (line, sizeof line, msg) == NULL) {
  384.             report (NONFATAL, 0, "read error on message");
  385.             return (RP_NO);    /* skip and go home */
  386.         }
  387.  
  388.         switch (hdr_parse (line, name, contents)) {
  389.             case HDR_NAM:    /* No name so contine
  390.                      * through header */
  391.             continue;
  392.  
  393.             case HDR_EOH:    /* End of header - lets go
  394.                      * home */
  395.             return (RP_OK);
  396.  
  397.             case HDR_NEW:
  398.             case HDR_MOR:    /* We have a valid field        */
  399.             if (lexequ (name, "to") == 0  ||
  400.                 lexequ (name, "cc") == 0||
  401.                 lexequ (name, "resent-to") == 0 ||
  402.                 lexequ (name, "resent-cc") == 0) {
  403.                 find_user (contents);
  404.                 break;
  405.             }
  406.             else if (lexequ (name, "resent-from") == 0) {
  407.                 if (from_adr)
  408.                     ap_free (from_adr);
  409.                 from_adr = AP_NIL;
  410.                 parse_addr (contents, &from_adr);
  411.                 break;
  412.             } else if (lexequ (name, "from") == 0) {
  413.                 parse_addr (contents, &from_adr);
  414.                 break;
  415.             }
  416.             else if (lexequ (name, "reply-to") == 0) {
  417.                 parse_addr (contents, &repl_adr);
  418.                 break;
  419.             }
  420.             else if (lexequ (name, "sender") == 0) {
  421.                 parse_addr (contents, &sndr_adr);
  422.                 break;
  423.             }
  424.             else if (lexequ (name, "subject") == 0) {
  425.                 strncpy (subj_field, contents,
  426.                      sizeof contents - 1);
  427.                 break;
  428.             }
  429.             else
  430.                 continue;
  431.         }
  432.     }
  433. }
  434.  
  435. /*
  436.  *    The real parser
  437.  */
  438.  
  439. hdr_parse (src, name, contents)    /* parse one header line         */
  440. register char *src;        /* a line of header text         */
  441. char   *name,            /* where to put field's name         */
  442.        *contents;        /* where to put field's contents     */
  443. {
  444.     extern char *compress ();
  445.     char    linetype;
  446.     register char *dest;
  447.  
  448. #ifdef    PP_DEBUG
  449.     report (TRACE, 0, "hdr_parse('%*.*s')", strlen(src)-1, strlen(src)-1, src);
  450. #endif
  451.  
  452.     if (isspace (*src)) {    /* continuation text             */
  453.  
  454. #ifdef    PP_DEBUG
  455.         report (TRACE, 0, "hrd_parse -> cmpnt more");
  456. #endif
  457.  
  458.         if (*src == '\n')
  459.             return (HDR_EOH);
  460.         linetype = HDR_MOR;
  461.     }
  462.     else {            /* copy the name             */
  463.         linetype = HDR_NEW;
  464.         for (dest = name; *dest = *src++; dest++) {
  465.             if (*dest == ':')
  466.                 break;    /* end of the name     */
  467.             if (*dest == '\n') {    /* oops, end of the
  468. line         */
  469.                 *dest = '\0';
  470.                 return (HDR_NAM);
  471.             }
  472.         }
  473.         *dest = '\0';
  474.         compress (name, name);    /* strip extra & trailing
  475.                      * spaces     */
  476.  
  477. #ifdef    PP_DEBUG
  478.         report (TRACE, 0, "hdr_parse -> cmpnt name '%s'", name);
  479. #endif
  480.     }
  481.  
  482.     for (dest = contents; isspace (*src);)
  483.         if (*src++ == '\n') {    /* skip leading white space
  484.      *//* u
  485.                      * nfulfilled promise, no
  486.                      * contents     */
  487.             *dest = '\0';
  488.             return ((linetype == HDR_MOR) ? HDR_EOH : linetype);
  489.         }        /* hack to fix up illegal spaces     */
  490.  
  491.     while ((*dest = *src) != '\n' && *src != 0)
  492.         src++, dest++;    /* copy contents and then, backup     */
  493.     while (isspace (*--dest));    /* to eliminate trailing
  494.                      * spaces     */
  495.     *++dest = '\0';
  496.  
  497.     return (linetype);
  498. }
  499.  
  500. /*************** Parsing of addresses got from message ***************/
  501.  
  502. /*
  503.  *    See if user is in this field. parse address first and
  504.  *        compare mbox's.
  505.  */
  506.  
  507. find_user (str)
  508. char   *str;
  509. {
  510.     AP_ptr  tree, local, domain;
  511.     ADDR    *ad;
  512.     RP_Buf    rp;
  513.     char   *p;
  514.  
  515. #ifdef    PP_DEBUG
  516.     report (TRACE, 0, "find_user('%s')", str);
  517. #endif
  518.  
  519.     if (found_1 == TRUE) {
  520.  
  521. #ifdef    PP_DEBUG
  522.         report (TRACE, 0, "find_user() name already found\n");
  523. #endif
  524.  
  525.         return;
  526.     }
  527.  
  528.     while ((str = ap_s2p (str, &tree, (AP_ptr *) 0, (AP_ptr *) 0, &local,
  529.              (AP_ptr *) &domain, (AP_ptr *) 0)) != (char *) DONE
  530.            && str != (char *) NOTOK) {
  531.         p = ap_p2s_nc (NULLAP, NULLAP, local, domain, NULLAP);
  532.  
  533.         ad = adr_new (p, AD_822_TYPE, 0);
  534.         ap_sqdelete (tree, NULLAP);
  535.         ap_free (tree);
  536.  
  537. #ifdef UKORDER
  538.         if (rp_isbad (ad_parse (ad, &rp, CH_UK_PREF))) {
  539. #else
  540.         if (rp_isbad (ad_parse (ad, &rp, CH_USA_PREF))) {
  541. #endif
  542.             adr_free (ad);
  543.             continue;
  544.         }
  545.         found_1 = (lexequ (ad -> ad_r822adr, user_adr -> ad_r822adr) == 0 ||
  546.             lexequ (p, username) == 0);
  547. #ifdef    PP_DEBUG
  548.         report (TRACE, 0, "find_user() -> found mbox %s (%s) ->%d",
  549.             p, user_adr -> ad_r822adr, found_1);
  550. #endif
  551.         free (p);
  552.         if (found_1 == TRUE)
  553.             return;
  554.     }
  555. }
  556.  
  557. /*
  558.  *    Attempt to parse a field into an address tree for later use.
  559.  */
  560.  
  561. parse_addr (str, aptr)
  562. char   *str;
  563. AP_ptr *aptr;
  564. {
  565.  
  566. #ifdef    PP_DEBUG
  567.     report (TRACE, 0, "parse_addr('%s')", str);
  568. #endif
  569.  
  570.     if (*aptr != NULLAP) {
  571.  
  572. #ifdef    PP_DEBUG
  573.         report (TRACE, 0, "field '%s' rejected, already seen one");
  574. #endif
  575.  
  576.         return;
  577.     }
  578.  
  579.     if ((*aptr = ap_s2t (str)) == (AP_ptr) NOTOK)
  580.     {    *aptr = NULLAP;
  581.         report (NONFATAL, 0, "Can't parse address '%s'", str);
  582.     }
  583. }
  584.  
  585. /*************** User Data Base Routines ***************/
  586.  
  587. /*
  588.  *    Note the fact we did/didnot reply to a given person
  589.  *    and include the subject line for good measure.
  590.  */
  591.  
  592. noteuser (addr, mode)
  593. char   *addr;
  594. int     mode;
  595. {
  596.     FILE   *fp;
  597.     time_t  now;
  598.     char   *ctime ();
  599.     int     result = NOTOK;
  600.  
  601. #ifdef    PP_DEBUG
  602.     report (TRACE, 0, "noteuser(%s,%d)", addr, mode);
  603. #endif
  604.  
  605.     time (&now);
  606.  
  607.     if ((fp = fopen (wholoc, "a")) != NULL) {
  608.         (void) chmod (wholoc, 0600);
  609.         fprintf (fp, "%c %-30s %19.19s >> %.20s\n",
  610.              mode == SENT ? REPLIED : NOT_REPLIED,
  611.              addr, ctime (&now), subj_field);
  612.         (void) fflush (fp);
  613.         result = ferror (fp) ? NOTOK : OK;
  614.         fclose (fp);
  615.         if (result == OK && mode == SENT) exit_code = 0;
  616.     }
  617.     return result;
  618. }
  619.  
  620. /*
  621.  *    Have we replied to this person before?
  622.  */
  623. checkuser (addr)
  624. char   *addr;
  625. {
  626.     FILE   *fp;
  627.     char    buffer[LINESIZE];
  628.     char    compaddr[LINESIZE];
  629.  
  630.     if (repeat_interval == 0)    return FALSE;
  631.  
  632.     if ((fp = fopen (wholoc, "r")) == NULL)
  633.         return FALSE;
  634.     while (fgets (buffer, sizeof buffer, fp) != NULL) {
  635.         if (buffer[0] == NOT_REPLIED)
  636.             continue;
  637.         /* SHOULD parse the date to see whether to repeat */
  638.         getaddress (buffer, compaddr);
  639.  
  640. #ifdef    PP_DEBUG
  641.         report (TRACE, 0, "checkuser, = '%s' & '%s'?", compaddr, addr);
  642. #endif
  643.  
  644.         if (lexequ (compaddr, addr) == 0) {
  645.             fclose (fp);
  646.             return TRUE;
  647.         }
  648.     }
  649.     fclose (fp);
  650.     return FALSE;
  651. }
  652.  
  653.  
  654. /*************** Some Utility Routines ***************/
  655.  
  656.  
  657. /*
  658.  *    Dig out a signature for the user
  659.  */
  660.  
  661. char   *find_sig ()
  662. {
  663.     FILE   *fp;
  664.     static char buf[LINESIZE];
  665.     static int been_here = FALSE;
  666.     char   *p;
  667.  
  668. #ifdef    PP_DEBUG
  669.     report (TRACE, 0, "find_sig()");
  670. #endif
  671.  
  672.     if (been_here == TRUE)    /* cuts off at least 1/4
  673.                  * micro-second */
  674.         return buf;
  675.  
  676.     if ((fp = fopen (sigloc, "r")) == NULL)
  677.         return NULLCP;
  678.     if (fgets (buf, sizeof (buf), fp) == NULLCP) {
  679.         fclose (fp);
  680.         return NULLCP;
  681.     }
  682.     if ((p = index (buf, '\n')) != NULLCP)
  683.         *p = '\0';
  684.     fclose (fp);
  685.     return buf;
  686. }
  687.  
  688. getaddress (source, dest)
  689. char   *source, *dest;
  690. {
  691.     register char *p;
  692.     int     depth = 0;
  693.  
  694.     p = source + 2;        /* skip over reply indicator */
  695.     while (*p) {
  696.         switch (*p) {
  697.             case '"':    /* in quoted part ? */
  698.             depth = !depth;
  699.             break;
  700.             case ' ':
  701.             case '\t':
  702.             if (depth == 0) {
  703.                 *dest = '\0';
  704.                 return;
  705.             }
  706.             break;
  707.             case '\\':    /* gobble up next char */
  708.             *dest++ = *p++;
  709.             break;
  710.         }
  711.         *dest++ = *p++;
  712.     }
  713.     *dest = '\0';
  714. }
  715.  
  716. /*VARARGS2*/
  717. report (mode, rc, fmt, a1, a2, a3, a4)
  718. int     mode;
  719. int    rc;
  720. char   *fmt, *a1, *a2, *a3, *a4;
  721. {
  722.     static FILE *log;
  723.  
  724.     if (debug == FALSE && mode == TRACE)
  725.         return;
  726.  
  727.     if (debug == TRUE) {
  728.         fprintf (stderr, "%s\t", mode == TRACE ? "TRACE" :
  729.              (mode == FATAL ? "FATAL" : "!FATAL"));
  730.         fprintf (stderr, fmt, a1, a2, a3, a4);
  731.         putc ('\n', stderr);
  732.         fflush (stderr);
  733.     }
  734.  
  735.     if (mode == FATAL)
  736.         exit (exit_rc(rc));    /* die a horrible death */
  737. }
  738.  
  739. static int exit_rc(num)
  740. int num;
  741. {
  742.     switch (exit_alg)
  743.     {
  744.     case 0:    return RP_MECH;
  745.     case 1:    return 0;
  746.     case 2:    return num;
  747.     default:return 0;
  748.     }
  749. }
  750.